home *** CD-ROM | disk | FTP | other *** search
- /******************************************************************************
- * trackball.c
- ******************************************************************************
- *
- * Purpose:
- * Descriptional text.
- *
- * Authors:
- * Michael Teschner and Christian Henn
- *
- * Note:
- * None.
- *
- * Revisions:
- * 10.11.93 micha Created file.
- *
- ******************************************************************************
- *
- * COPYRIGHT (C) 1992, 1993, 1994
- *
- * BY CHRISTIAN HENN M.E. MUELLER-INSTITUTE FOR MICROSCOPY (MIM)
- * HENN@COMP.BIOZ.UNIBAS.CH CH-4056 BASEL, SWITZERLAND
- *
- * AND MICHAEL WALDHERR-TESCHNER SILICON GRAPHICS INDUSTRIES (SGI)
- * MICHA@BASEL.SGI.COM CH-4125 RIEHEN, SWITZERLAND
- *
- ******************************************************************************
- *
- * PERMISSION TO USE, COPY, MODIFY AND DISTRIBUTE THIS SOFTWARE AND ITS DOCU-
- * MENTATION FOR THE PURPOSE OF RESEARCH, DEVELOPMENT AND EDUCATION IS HEREBY
- * GRANTED FREE OF CHARGE, SUBJECT TO THE FOLLOWING RESTRICTIONS:
- *
- * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS,
- * IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF DESIGN,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR ARISING FROM A
- * COURSE OF DEALING, USAGE OR TRADE PRACTICE.
- *
- * IN NO EVENT SHALL SILICON GRAPHICS OR THE M.E. MUELLER-INSTITUTE BE LIABLE
- * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
- * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
- * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
- * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
- * THIS SOFTWARE.
- *
- ******************************************************************************
- */
- /*
- * Implementation of a virtual trackball. See trackball.h for the
- * interface to these routines.
- * Implemented by Gavin Bell, lots of ideas from Thant Tessman and
- * the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129.
- */
- #include <stdio.h>
- #include <math.h>
- #include <device.h>
- #include "trackball.h"
-
-
- /*** michael teschner ***/
-
- do_trackball()
- {
- int i;
- pushmatrix();
-
- /** trackball starts here */
-
- if( getbutton(LEFTMOUSE)) {
-
- nmx = getvaluator(MOUSEX);
- nmy = getvaluator(MOUSEY);
-
-
- if( nmx == omx && nmy == omy ) {
- spr[0] = spr[1] = spr[2] = 0;
- spr[3] = 1;
- popmatrix();
- return;
- }
-
-
- if( getbutton(LEFTSHIFTKEY) || getbutton(RIGHTSHIFTKEY) ){
- if(getbutton(MIDDLEMOUSE)) {
- g_tz -= (nmy-omy) / 20.0;
-
- }
- else{
- g_tx += (nmx - omx) /20.0;
- g_ty += (nmy - omy) /20.0;
- }
- goto lab;
- }
-
- if( getbutton(MIDDLEMOUSE) ){
- gr_sca = gr_sca - (nmy-omy)/100.0;
- if( gr_sca < 0 ) gr_sca = 0.0;
- omx = nmx; omy = nmy;
- }
- else{
-
-
- u_to_wo(omx-w_ox, omy-w_oy, &p1x, &p1y);
- u_to_wo(nmx-w_ox, nmy-w_oy, &p2x, &p2y);
-
- trackball( r, p1x, p1y, p2x, p2y);
-
-
- loadmatrix(imat);
-
- rot(-r[0],'x'); rot(-r[1],'y'); rot(-r[2],'z');
- multmatrix(mat);
-
- getmatrix(mat);
-
- loadmatrix(imat);
-
- multmatrix(rmat);
- rot(r[0],'x'); rot(r[1],'y'); rot(r[2],'z');
-
- getmatrix(rmat);
-
-
- for(i=0;i<4;i++) spr[i] = r[i];
- lab:
- omx = nmx; omy = nmy;
- }
- }
-
- else{
- /* no spinning - comment out the next 4 lines */
- loadmatrix(imat);
- rot(-spr[0],'x'); rot(-spr[1],'y'); rot(-spr[2],'z');
- multmatrix(mat);
- getmatrix(mat);
- loadmatrix(imat);
- multmatrix(rmat);
- rot(spr[0],'x'); rot(spr[1],'y'); rot(spr[2],'z');
- getmatrix(rmat);
-
- omx = getvaluator(MOUSEX);
- omy = getvaluator(MOUSEY);
- }
-
- popmatrix();
- } /* end do_trackball */
-
- do_clipp()
- {
- int i;
- pushmatrix();
-
- /** trackball starts here */
-
- if( getbutton(LEFTMOUSE)) {
-
- nmx = getvaluator(MOUSEX);
- nmy = getvaluator(MOUSEY);
-
-
- if( nmx == omx && nmy == omy ) {
- spr[0] = spr[1] = spr[2] = 0;
- spr[3] = 1;
- popmatrix();
- return;
- }
-
-
- if( getbutton(LEFTSHIFTKEY) || getbutton(RIGHTSHIFTKEY) ){
-
- cp_tr -= (nmy - omy) /10.0;
- omx = nmx; omy = nmy;
- popmatrix();
- return;
- }
-
- if( getbutton(DKEY) ){
- cp_dt -= (nmy - omy) /10.0;
- omx = nmx; omy = nmy;
- popmatrix();
- return;
- }
-
-
-
-
- u_to_wo(omx-w_ox, omy-w_oy, &p1x, &p1y);
- u_to_wo(nmx-w_ox, nmy-w_oy, &p2x, &p2y);
-
- trackball( r, p1x, p1y, p2x, p2y);
-
-
- loadmatrix(imat);
- cp_xr += r[0]*3;
- cp_yr += r[1]*3;
-
- for(i=0;i<4;i++) spr[i] = r[i];
- omx = nmx; omy = nmy;
-
- }
-
- else{
- /* no spinning - comment out the next 4 lines */
-
-
- omx = getvaluator(MOUSEX);
- omy = getvaluator(MOUSEY);
- }
-
- popmatrix();
- } /* end do_clipp */
-
-
- sbr_ini_trackball(int id)
- {
-
- track_window = id;
-
- r[0] = r[1] = r[2] = 0.0;
- r[3] = 1.0;
-
- spr[0] = spr[1] = spr[2] = 0.0;
- spr[3] = 1.0;
-
- gr_sca = 1.0;
-
- get_win_par();
- sbr_reset_mat();
-
-
- }
-
- get_win_par()
- {
- winset(track_window);
- getsize( &w_xsiz, &w_ysiz);
- getorigin(&w_ox, &w_oy);
-
- cx = (w_ox + w_xsiz/2.0);
- cy = (w_oy + w_ysiz/2.0);
-
- }
-
- sbr_reset_cp()
- {
- cp_xr = cp_yr = cp_tr = 0.0;
- cp_dt = 2.0;
- }
- sbr_reset_mat()
- {
- int i, j;
-
- for(i=0;i<4;i++)
- for(j=0;j<4;j++){
- if( i == j ) imat[i][j] = mat[i][j] = rmat[i][j] = 1.0;
- else imat[i][j] = mat[i][j] = rmat[i][j] = 0.0;
- }
-
- g_tx = g_ty = g_tz = 0.0;
- }
-
- /* transformation from window-coordinates to world-coordinates */
- void u_to_wo(long sx, long sy, float *wx, float *wy)
- {
- *wx = (2.0 * sx) / (float) w_xsiz - 1.0;
- *wy = (2.0 * sy) / (float) w_ysiz - 1.0;
- }
-
-
- /***** *******/
-
- /* Size of virtual trackball, in relation to window size */
- float trackballsize = 0.4;
-
- /* Function prototypes for local functions */
- float tb_project_to_sphere(float r, float x, float y);
- void normalize_euler(float *e);
-
- /*
- * Ok, simulate a track-ball. Project the points onto the virtual
- * trackball, then figure out the axis of rotation, which is the cross
- * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)
- * Note: This is a deformed trackball-- is a trackball in the center,
- * but is deformed into a hyperbolic solid of rotation away from the
- * center.
- *
- * It is assumed that the arguments to this routine are in the range
- * (-1.0 ... 1.0)
- */
- void trackball(float *e, float p1x, float p1y, float p2x, float p2y)
- {
- float p1[3];
- float p2[3];
- float d[3];
- float phi; /* how much to rotate about axis */
- float a[3]; /* Axis of rotation */
- int i;
- vzero(a);
-
- if (p1x == p2x && p1y == p2y)
- {
- vzero(e); /* Zero rotation */
- e[3] = 1.0;
- return ;
- }
-
- /*
- * First, figure out z-coordinates for projection of P1 and P2 to
- * deformed sphere
- */
- vset(p1, p1x, p1y, tb_project_to_sphere(trackballsize, p1x, p1y));
- vset(p2, p2x, p2y, tb_project_to_sphere(trackballsize, p2x, p2y));
-
- /*
- * Now, we want the cross product of P1 and P2
- * (Or cross product of p2 and p1... this was determined by trial and
- * error, so there may be a compensating mathematical boo-boo
- * somewhere else).
- */
-
- vcross(p2, p1, a);
-
- /*
- * Figure out how much to rotate around that axis.
- */
- vsub(p1, p2, d);
- phi = fsin(vlength(d) / (2.0 * trackballsize));
-
- axis_to_euler(a, phi, e);
-
- for(i=0;i<3;i++) e[i] = e[i] * 180 / M_PI;
- }
-
- /*
- * Given an axis and angle, compute euler paramaters
- */
- void axis_to_euler(float *a, float phi, float *e)
- {
- vnormal(a); /* Normalize axis */
- vcopy(a, e);
- vscale(e, fsin(phi/2.0));
- e[3] = fcos(phi/2.0);
- }
-
- /*
- * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
- * if we are away from the center of the sphere.
- */
- float tb_project_to_sphere(float r, float x, float y)
- {
- float d, t, z;
-
- d = sqrt(x*x + y*y);
- if (d < r*M_SQRT1_2) /* Inside sphere */
- {
- z = sqrt(r*r - d*d);
- }
- else /* On hyperbola */
- {
- t = r / M_SQRT2;
- z = t*t / d;
- }
- return z;
- }
-
- /*
- * Given two rotations, e1 and e2, expressed as Euler paramaters,
- * figure out the equivalent single rotation and stuff it into dest.
- *
- * This routine also normalizes the result every COUNT times it is
- * called, to keep error from creeping in.
- */
- #define COUNT 100
- void add_eulers(float *e1, float *e2, float *dest)
- {
- static int count=0;
- register int i;
- float t1[3], t2[3], t3[3];
- float tf[4];
-
- vcopy(e1, t1); vscale(t1, e2[3]);
- vcopy(e2, t2); vscale(t2, e1[3]);
- vcross(e2, e1, t3);
- vadd(t1, t2, tf);
- vadd(t3, tf, tf);
- tf[3] = e1[3] * e2[3] - vdot(e1, e2);
-
- for (i = 0 ; i < 4 ;i++)
- {
- dest[i] = tf[i];
- }
-
- if (++count > COUNT)
- {
- count = 0;
- normalize_euler(dest);
- }
- }
-
- /*
- * Euler paramaters always obey: a^2 + b^2 + c^2 + d^2 = 1.0
- * We'll normalize based on this formula. Also, normalize greatest
- * component, to avoid problems that occur when the component we're
- * normalizing gets close to zero (and the other components may add up
- * to more than 1.0 because of rounding error).
- */
- void normalize_euler(float *e)
- { /* Normalize result */
- int which, i;
- float gr;
-
- which = 0;
- gr = e[which];
- for (i = 1 ; i < 4 ; i++)
- {
- if (fabs(e[i]) > fabs(gr))
- {
- gr = e[i];
- which = i;
- }
- }
-
- e[which] = 0.0;
-
- e[which] = fsqrt(1.0 - (e[0]*e[0] + e[1]*e[1] +
- e[2]*e[2] + e[3]*e[3]));
-
- /* Check to see if we need negative square root */
- if (gr < 0.0)
- e[which] = -e[which];
- }
-
- /*
- * Build a rotation matrix, given Euler paramaters.
- */
- void build_rotmatrix(Matrix m, float *e)
- {
- m[0][0] = 1 - 2.0 * (e[1] * e[1] + e[2] * e[2]);
- m[0][1] = 2.0 * (e[0] * e[1] - e[2] * e[3]);
- m[0][2] = 2.0 * (e[2] * e[0] + e[1] * e[3]);
- m[0][3] = 0.0;
-
- m[1][0] = 2.0 * (e[0] * e[1] + e[2] * e[3]);
- m[1][1] = 1 - 2.0 * (e[2] * e[2] + e[0] * e[0]);
- m[1][2] = 2.0 * (e[1] * e[2] - e[0] * e[3]);
- m[1][3] = 0.0;
-
- m[2][0] = 2.0 * (e[2] * e[0] - e[1] * e[3]);
- m[2][1] = 2.0 * (e[1] * e[2] + e[0] * e[3]);
- m[2][2] = 1 - 2.0 * (e[1] * e[1] + e[0] * e[0]);
- m[2][3] = 0.0;
-
- m[3][0] = 0.0;
- m[3][1] = 0.0;
- m[3][2] = 0.0;
- m[3][3] = 1.0;
- }
-
- /** originally from the file vect.c **/
-
- /*
- * vect -
- * Various functions to support operations on vectors.
- *
- * David M. Ciemiewicz, Mark Grossman, Henry Moreton, and Paul Haeberli
- *
- * Modified for my own nefarious purposes-- Gavin Bell
- * prototyping : pff
- */
-
- float *vnew(void)
- {
- register float *v;
-
- v = (float *) malloc(sizeof(float)*3);
- return v;
- }
-
- float *vclone(float *v)
- {
- register float *c;
-
- c = vnew();
- vcopy(v, c);
- return c;
- }
-
- void vcopy(float *v1, float *v2)
- {
- register int i;
- for (i = 0 ; i < 3 ; i++)
- v2[i] = v1[i];
- }
-
- void vprint(float *v)
- {
- printf("x: %f y: %f z: %f\n",v[0],v[1],v[2]);
- }
-
- void vset(float *v, float x, float y, float z)
- {
- v[0] = x;
- v[1] = y;
- v[2] = z;
- }
-
- void vzero(float *v)
- {
- v[0] = 0.0;
- v[1] = 0.0;
- v[2] = 0.0;
- }
-
- void vnormal(float *v)
- {
- vscale(v,1.0/vlength(v));
- }
-
- float vlength(float *v)
- {
- return fsqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
- }
-
- void vscale(float *v, float div)
- {
- v[0] *= div;
- v[1] *= div;
- v[2] *= div;
- }
-
- void vmult(float *src1, float *src2, float *dst)
- {
- dst[0] = src1[0] * src2[0];
- dst[1] = src1[1] * src2[1];
- dst[2] = src1[2] * src2[2];
- }
-
- void vadd(float *src1, float *src2, float *dst)
- {
- dst[0] = src1[0] + src2[0];
- dst[1] = src1[1] + src2[1];
- dst[2] = src1[2] + src2[2];
- }
-
- void vsub(float *src1, float *src2, float *dst)
- {
- dst[0] = src1[0] - src2[0];
- dst[1] = src1[1] - src2[1];
- dst[2] = src1[2] - src2[2];
- }
-
- void vhalf(float *v1, float *v2, float *half)
- {
- float len;
-
- vadd(v2,v1,half);
- len = vlength(half);
- if(len>0.0001)
- vscale(half,1.0/len);
- else
- *half = *v1;
- }
-
- float vdot(float *v1, float *v2)
- {
- return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
- }
-
- void vcross(float *v1, float *v2, float *cross)
- {
- float temp[3];
-
- temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]);
- temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]);
- temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]);
- vcopy(temp, cross);
- }
-
- void vdirection(float *v1, float *dir)
- {
- *dir = *v1;
- vnormal(dir);
- }
-
- void vreflect(float *in, float *mirror, float *out)
- {
- float temp[3];
-
- vcopy(mirror, temp);
- vscale(temp,vdot(mirror,in));
- vsub(temp,in,out);
- vadd(temp,out,out);
- }
-
- void vmultmatrix(float m1[][4], float m2[][4], float prod[][4])
- {
- register int row, col;
- float temp[4][4];
-
- for(row=0 ; row<4 ; row++)
- for(col=0 ; col<4 ; col++)
- temp[row][col] = m1[row][0] * m2[0][col]
- + m1[row][1] * m2[1][col]
- + m1[row][2] * m2[2][col]
- + m1[row][3] * m2[3][col];
- for(row=0 ; row<4 ; row++)
- for(col=0 ; col<4 ; col++)
- prod[row][col] = temp[row][col];
- }
-
- void vtransform(float *v, float mat[][4], float *vt)
- {
- float t[3];
-
- t[0] = v[0]*mat[0][0] + v[1]*mat[1][0] + v[2]*mat[2][0] + mat[3][0];
- t[1] = v[0]*mat[0][1] + v[1]*mat[1][1] + v[2]*mat[2][1] + mat[3][1];
- t[2] = v[0]*mat[0][2] + v[1]*mat[1][2] + v[2]*mat[2][2] + mat[3][2];
- vcopy(t, vt);
- }
-